using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
using TelnetExpect;
using System.IO;

namespace TelnetTests
{
    [TestFixture]
    public class TelnetBaseStream_Other_Tests
    {
        [Test]
        public void AAARGGGGH_codecoverage_fake()
        {
            TelnetBaseStream telnet = new TelnetBaseStream(new MemoryStream());
            //
            Assert.IsTrue(telnet.CanRead, "CanRead");
            Assert.IsTrue(telnet.CanWrite, "CanWrite");
            //
            telnet.Flush();
        }

        [Test]
        public void StreamNoSeekEtc()
        {
            TelnetBaseStream telnet = new TelnetBaseStream(new MemoryStream());
            //
            try {
                long L = telnet.Length;
                Assert.Fail("should have thrown!");
            } catch {
            }
            try {
                telnet.SetLength(10);
                Assert.Fail("should have thrown!");
            } catch (NotSupportedException) {
            }
            //
            Assert.IsFalse(telnet.CanSeek, "CanSeek"); //????
            //
            try {
                telnet.Seek(1, SeekOrigin.Current);
                Assert.Fail("should have thrown!");
            } catch (NotSupportedException) {
            }
            try {
                long L = telnet.Position;
                Assert.Fail("should have thrown!");
            } catch (NotSupportedException) {
            }
            try {
                telnet.Position = 10;
                Assert.Fail("should have thrown!");
            } catch (NotSupportedException) {
            }
        }

        [Test]
        public void CtorArgEx()
        {
            try {
                new TelnetBaseStream(null);
                Assert.Fail("should have thrown!");
            } catch (ArgumentNullException) {
            }
            try {
                Stream nonWriteableStream = new MemoryStream(new byte[5], false);
                new TelnetBaseStream(nonWriteableStream);
                Assert.Fail("should have thrown!");
            } catch (ArgumentException) {
            }
            try {
                Stream nonReadableStream = new CanReadFalseStream();
                new TelnetBaseStream(nonReadableStream);
                Assert.Fail("should have thrown!");
            } catch (ArgumentException) {
            }
        }

        [Test]
        public void DiscardsAnyRcvdSubNegotiation()
        {
            byte[] input = { TestsBase.IAC, TestsBase.SB,
                OptionCode.BinaryTransmission,
                1,2,3,4,
                TestsBase.IAC, TestsBase.SE,
                //
                (byte)'a', (byte)'b', (byte)'c',
            };
            byte[] expectedInput = { (byte)'a', (byte)'b', (byte)'c',
            };
            TelnetBaseStream telnet = Create_Testee(input);
            byte[] buf = new byte[100];
            int readLen = telnet.Read(buf, 0, buf.Length);
            Assert.AreEqual(3, readLen);
            TestsBase.Assert_Buffers_AreEqual(expectedInput, buf, 0, readLen, "expectedInput");
        }

        private static TelnetBaseStream Create_Testee(byte[] input)
        {
            MemoryStream dst;
            return Create_Testee(input, out dst);
        }

        private static TelnetBaseStream Create_Testee(byte[] input, out MemoryStream dst)
        {
            Stream src = new MemoryStream(input, false);
            dst = new MemoryStream();
            PairStream peer = new PairStream(src, dst);
            TelnetBaseStream telnet = new TelnetBaseStream(peer);
            return telnet;
        }

        //--------
        [Test]
        public void SendCommand()
        {
            byte[] input = {
            };
            byte[] expectedInput = { (byte)'a', (byte)'b', (byte)'c',
            };
            MemoryStream dst;
            TelnetBaseStream telnet = Create_Testee(input, out dst);
            byte[] buf = new byte[100];
            //
            telnet.SendTelnetCommand(TelnetBaseStream.Command.AYT);
            TestsBase.Assert_Buffers_AreEqual(
                new byte[] { 255,246 },
                dst, "AYT");
            telnet.SendTelnetCommand(TelnetBaseStream.Command.EC);
            TestsBase.Assert_Buffers_AreEqual(
                new byte[] { 255, 246, /**/ 255, 247 },
                dst, "AYT-EC");
            telnet.SendTelnetCommand((TelnetBaseStream.Command)5);
            TestsBase.Assert_Buffers_AreEqual(
                new byte[] { 255, 246, /**/ 255, 247, /**/ 255, 5, },
                dst, "AYT-EC-misc");
            TelnetBaseStream.Command eor = (TelnetBaseStream.Command)239;
            telnet.SendTelnetCommand(eor);
            TestsBase.Assert_Buffers_AreEqual(
                new byte[] { 255, 246, /**/ 255, 247, /**/ 255, 5, /**/ 255, 239 },
                dst, "AYT-EC-misc-EOR");
        }

        [Test]
        public void SendCommand_Disallowed()
        {
            TelnetBaseStream telnet = Create_Testee(new byte[0]);
            object[] disallowed = {
                TelnetBaseStream.Command.Do, TelnetBaseStream.Command.Dont,
                TelnetBaseStream.Command.Will, TelnetBaseStream.Command.Wont,
                255, // IAC
                TelnetBaseStream.Command.SB, TelnetBaseStream.Command.SE,
            };
            foreach (object curO in disallowed) {
                TelnetBaseStream.Command cur;
                if (curO is int) {
                    cur = checked((TelnetBaseStream.Command)(int)curO);
                } else {
                    cur = (TelnetBaseStream.Command)curO;
                }
                try {
                    telnet.SendTelnetCommand(cur);
                    Assert.Fail("should have thrown! -- " + cur);
                } catch (ArgumentException) {
                }
            }
            //manually
            try {
                telnet.SendTelnetCommand(TelnetBaseStream.Command.Do);
                Assert.Fail("should have thrown!");
            } catch (ArgumentException) {
            }
            try {
                telnet.SendTelnetCommand(TelnetBaseStream.Command.Dont);
                Assert.Fail("should have thrown!");
            } catch (ArgumentException) {
            }
            try {
                telnet.SendTelnetCommand(TelnetBaseStream.Command.Will);
                Assert.Fail("should have thrown!");
            } catch (ArgumentException) {
            }
            try {
                telnet.SendTelnetCommand(TelnetBaseStream.Command.Wont);
                Assert.Fail("should have thrown!");
            } catch (ArgumentException) {
            }
            //
            try {
                TelnetBaseStream.Command iac = (TelnetBaseStream.Command)255;
                telnet.SendTelnetCommand(iac);
                Assert.Fail("should have thrown!");
            } catch (ArgumentException) {
            }
        }

        //--------
        [Test]
        public void UtilShowControlChars_Char()
        {
            DoTest_ShowControlChars_Char('a', "a");
            DoTest_ShowControlChars_Char('9', "9");
            DoTest_ShowControlChars_Char('\x000d', @"\r");
            DoTest_ShowControlChars_Char('\x000a', @"\n");
            DoTest_ShowControlChars_Char('\x0009', @"\t");
        }

        private static void DoTest_ShowControlChars_Char(char input, string expected)
        {
            string r = TelnetBaseStream.UtilityShowControlChars(input);
            Assert.AreEqual(expected, r);
        }

        [Test]
        public void UtilShowControlChars_String1()
        {
            DoTest_ShowControlChars_String("a", "a");
            DoTest_ShowControlChars_String("9", "9");
            DoTest_ShowControlChars_String("\x000d", @"\r");
            DoTest_ShowControlChars_String("\x000a", @"\n");
            DoTest_ShowControlChars_String("\x0009", @"\t");
            DoTest_ShowControlChars_String("\x0000", @"\x0000");
            DoTest_ShowControlChars_String("\x001f", @"\x001f");
        }

        [Test,
        ExpectedException(typeof(ArgumentNullException))]
        public void UtilShowControlChars_String_Null()
        {
            TelnetBaseStream.UtilityShowControlChars(null);
        }

        [Test]
        public void UtilShowControlChars_StringN()
        {
            DoTest_ShowControlChars_String("a\x000d\x000a\x0009\x00009", @"a\r\n\t\x00009");
        }

        private static void DoTest_ShowControlChars_String(string input, string expected)
        {
            string r = TelnetBaseStream.UtilityShowControlChars(input);
            Assert.AreEqual(expected, r);
        }

        //--------
        //[Test]
        //public void Escape255s_No255s_OffsetBuffer()
        //{
        //    byte[] input = 
        //}

    }
}
